#include <iostream>
#include <mutex>
#include <thread>

#include "chat_codec.h"
#include "xlcomm/net/event_loop_thread.h"
#include "xlcomm/net/tcp_client.h"
using namespace xlcomm;

class ChatClient {
 public:
  ChatClient(net::EventLoop* loop, const net::InetAddress& server_addr)
      : loop_(loop),
        client_(loop, server_addr, "ChatClient"),
        codec_(std::bind(&ChatClient::OnStringMessage, this, _1, _2, _3)) {
    client_.set_connect_callback(
        std::bind(&ChatClient::OnConnection, this, _1));
    client_.set_disconnect_callback(
        std::bind(&ChatClient::OnConnection, this, _1));
    client_.set_message_callback(
        std::bind(&ChatCodec::OnMessage, &codec_, _1, _2, _3));
  }

  void Connect() { client_.Connect(); }

  void Send(const std::string& msg) {
    std::lock_guard<std::mutex> guard(mutex_);
    if (conn_) {
      codec_.Send(conn_, msg);
    }
  }

  void Quit() { client_.Disconnect(); }

 private:
  void OnConnection(const net::TcpConnectionPtr& conn) {
    std::lock_guard<std::mutex> guard(mutex_);
    if (conn->IsConnected()) {
      conn_ = conn;
    } else {
      conn_.reset();
    }
  }

  void OnStringMessage(const net::TcpConnectionPtr& conn,
                       const std::string& msg, Timestamp recv_time) {
    // 由EventLoop线程调用，printf不用加锁，因为它是线程安全的（std::cout不是线程安全的）
    printf("len:%zu msg:%s\n", msg.length(), msg.c_str());
  }

  net::EventLoop* loop_;
  net::TcpClient client_;
  net::TcpConnectionPtr conn_;
  std::mutex mutex_;
  ChatCodec codec_;
};

int main(int argc, const char* argv[]) {
  net::EventLoopThread loop_thread;
  ChatClient client(loop_thread.StartLoop(),
                    net::InetAddress(30001, argc == 2 ? argv[1] : "127.0.0.1"));
  client.Connect();

  std::string input;
  while (std::getline(std::cin, input)) {
    client.Send(input);
  }
}